Skip to content

fix(rsc): handle export * re-exports in use client modules#1234

Open
james-elicx wants to merge 3 commits into
vitejs:mainfrom
james-elicx:claude/busy-raman-3dee83
Open

fix(rsc): handle export * re-exports in use client modules#1234
james-elicx wants to merge 3 commits into
vitejs:mainfrom
james-elicx:claude/busy-raman-3dee83

Conversation

@james-elicx
Copy link
Copy Markdown
Contributor

@james-elicx james-elicx commented May 21, 2026

Summary

The use-client proxy transform in @vitejs/plugin-rsc throws unsupported ExportAllDeclaration whenever a "use client" file contains export * from '...'. Reported downstream in cloudflare/vinext#1352, where Next.js's app-dir test suite hits this with a real-world components/export-all/index.js fixture.

fixes #1233

Reproduction

A new fixture under packages/plugin-rsc/examples/basic/src/routes/export-all/ reproduces the original error on main:

[plugin rsc:use-client] .../routes/export-all/index.tsx
Error: unsupported ExportAllDeclaration
    at transformProxyExport (.../transforms/index.js:338:90)

It builds cleanly with the fix.

Fix

  1. Pure transforms (proxy-export.ts, wrap-export.ts) now handle the export * as ns from '...' form directly, since the namespace name is statically known.

  2. Plugin layer (plugin.ts) introduces an expandExportAllDeclarations helper used by both vitePluginUseClient and vitePluginUseServer. For each bare export * from '...' declaration, it resolves the source, recursively collects the named exports via AST walk, and rewrites the source to export { a, b, c } from '...' before the proxy transform runs. This mirrors what Next.js's webpack plugin does to pre-resolve export * into named exports.

    • In build mode it uses this.load({ id }).code (which Rollup populates).
    • In dev mode ModuleInfo.code is unsupported and transformRequest returns module-runner output (__vite_ssr_exportName__(...)) that lacks readable ESM exports, so it falls back to fs.readFile + transformWithOxc to get standard JS the AST walk can read.

Test plan

  • New unit coverage in proxy-export.test.ts for export * as ns from, the post-resolution form, the ignoreExportAllDeclaration escape hatch, and the still-thrown unresolved-bare case; updated wrap-export.test.ts snapshot. All 428 unit tests pass.
  • New e2e test export * in basic.test.ts against the new fixture. All 151 basic e2e tests pass in both dev and build modes.
  • Verified original build error reproduces on main (stashed the fix, rebuilt, build fails with the exact error from the issue) and disappears with the fix.

The `use-client` proxy transform threw `unsupported ExportAllDeclaration`
on any `"use client"` file containing `export * from '...'`. Pre-resolve
bare `export *` declarations to explicit named re-exports before running
the proxy transform (mirroring Next.js's webpack plugin behavior), and
handle `export * as ns from` directly in the pure proxy/wrap transforms
since the name is statically known.

Closes cloudflare/vinext#1352
@james-elicx james-elicx marked this pull request as ready for review May 21, 2026 21:41
@hi-ogawa hi-ogawa self-assigned this May 22, 2026
Comment thread packages/plugin-rsc/src/plugin.ts Outdated
Copy link
Copy Markdown
Contributor

@hi-ogawa hi-ogawa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. The idea makes sense to me.

@james-elicx james-elicx requested a review from hi-ogawa May 22, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[plugin-rsc] use-client transform throws on export * from (ExportAllDeclaration)

2 participants